package com.example.a10928.weifriend.util;

import android.app.Activity;
import android.databinding.ObservableField;
import android.databinding.ObservableMap;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;

import com.example.a10928.weifriend.App;
import com.example.a10928.weifriend.http.configuration.ApiException;
import com.example.a10928.weifriend.http.configuration.CodeErrorShowException;
import com.google.gson.Gson;

import java.io.IOException;
import java.net.ConnectException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.ObservableTransformer;
import io.reactivex.Single;
import io.reactivex.SingleTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Action;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import me.leefeng.promptlibrary.PromptDialog;

/**
 * Created by ipcjs on 2017/07/09.
 */

public class RxUtil {
    public static final Object NULL = "";

    private RxUtil() {
    }

    public static void dispose(Disposable... ds) {
        for (Disposable d : ds) {
            if (d != null && !d.isDisposed()) {
                d.dispose();
            }
        }
    }

    public static <R> Disposable workWithUiResult(Supplier<R> workAction, Consumer<R> uiAction, Consumer<Throwable> error) {
        return Single.just(NULL)
                .map(o -> workAction.get())
                .compose(io2mainSingle())
                .subscribe(uiAction, error);
    }

    public static <T> SingleTransformer<T, T> io2mainSingle() {
        return single -> single
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

    public static <T> ObservableTransformer<T, T> io2main() {
        return observable -> observable
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

    public static <T> ObservableTransformer<T, T> io2mainLoad(Activity activity) {
        //这个加载框在一个activity同时只能有一个出现，否则报NullPoint错误
        PromptDialog dialog=new PromptDialog(activity);
        return observable -> observable
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .doOnSubscribe(r->{
                dialog.showLoading("加载中");
            }
            )
            .doFinally(new Action() {
                @Override
                public void run() {
                    dialog.dismiss();

                    try {
                        App.handler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                            }
                        },500);
                    } catch (Exception e) {
                        L.t("挂了");
                    }
                }


            }

            );
    }

    /**
     * 添加个最小延时, 用来防止有时加载太快, 看不到进度条的情况...
     * @param minDelay
     * @param <T>
     * @return
     */
    public static <T> ObservableTransformer<T, T> minDelay(long minDelay) {
        return observable -> observable.timeInterval().flatMap(timed -> {
            long delta = minDelay - timed.time(TimeUnit.MILLISECONDS);
            return Observable.just(timed.value()).delay(delta > 0 ? delta : 0, TimeUnit.MILLISECONDS);
        });
    }

//
//    public static <T> ObservableTransformer<T, T> minDelay() {
//        return minDelay(DelayApiCallback.DEFAULT_MIN_DELAY);
//    }

    public interface Supplier<T> {
        /**
         * Retrieves an instance of the appropriate type. The returned object may or
         * may not be com.a new instance, depending on the implementation.
         * @return an instance of the appropriate type
         */
        @NonNull
        T get() throws Exception;
    }

    public static <T> Observable<T> wrap(ObservableField<T> field) {
        return wrap(field, false);
    }

    /** 包装data binding的变量改变 */
    public static <T> Observable<T> wrap(ObservableField<T> field, boolean sendFirstValue) {
        return Observable.create(e -> {
            android.databinding.Observable.OnPropertyChangedCallback callback = new android.databinding.Observable.OnPropertyChangedCallback() {
                @Override
                public void onPropertyChanged(android.databinding.Observable observable, int i) {
                    e.onNext(field.get());
                }
            };
            field.addOnPropertyChangedCallback(callback);
            e.setCancellable(() -> field.removeOnPropertyChangedCallback(callback));
            if (sendFirstValue) {
                e.onNext(field.get());
            }
        });
    }

/*    public static <T> Observable<ObservableList<T>> wrap(final ObservableList<T> list) {
        return wrap(list, false);
    }*/

   /* public static <T> Observable<ObservableList<T>> wrap(final ObservableList<T> list, boolean sendFirstValue) {
        return Observable.create(e -> {
            SimpleOnListChangedCallback<ObservableList<T>> callback = new SimpleOnListChangedCallback<ObservableList<T>>() {
                @Override
                public void onChanged(ObservableList<T> sender) {
                    e.onNext(list);
                }
            };
            list.addOnListChangedCallback(callback);
            e.setCancellable(() -> list.removeOnListChangedCallback(callback));
            if (sendFirstValue) {
                e.onNext(list);
            }
        });
    }*/

    public static <K, V> Observable<ObservableMap<K, V>> wrap(final ObservableMap<K, V> map) {
        return wrap(map, false);
    }

    public static <K, V> Observable<ObservableMap<K, V>> wrap(final ObservableMap<K, V> map, boolean sendFirstValue) {
        return Observable.create(e -> {
            ObservableMap.OnMapChangedCallback<ObservableMap<K, V>, K, V> callback = new ObservableMap.OnMapChangedCallback<ObservableMap<K, V>, K, V>() {
                @Override
                public void onMapChanged(ObservableMap<K, V> sender, K key) {
                    e.onNext(map);
                }
            };
            map.addOnMapChangedCallback(callback);
            e.setCancellable(() -> map.removeOnMapChangedCallback(callback));
            if (sendFirstValue) {
                e.onNext(map);
            }
        });
    }

    /**
     * 若异常为RuntimeException则抛出, 否则打印异常
     */
    public static void throwRuntimeExceptionOrPrint(Throwable e) {
        if (e instanceof RuntimeException) {
            throw (RuntimeException) e;
        }
        e.printStackTrace();
    }

    public static <T> T gsonDataString(String data, Class<T> tClass){
        Gson gson = new Gson();
        T  t = gson.fromJson(data, tClass);
        return t;
    }
//
//    public static <T> List<T> gsonDataStringArray(String data, Class<T> tClass){
//       return JSON.parseArray(data, tClass);
//    }

    public static void errorException(Throwable e){
        if(e instanceof ConnectException){
            Utils.getIsNetWork().set(false);
            L.t("请检查网络，无法连接服务器");
            return ;
        }
        if (e instanceof ApiException)
            CodeErrorShowException.show(((ApiException) e).getCode(), ((ApiException) e).getMsg());
    }
}
